package com.cskaoyan.service;

import com.cskaoyan.bean.*;
import com.cskaoyan.bean.address.WXAddress;
import com.cskaoyan.bean.cart.bo.AddToCartBo;
import com.cskaoyan.bean.cart.bo.CartCheckoutBo;
import com.cskaoyan.bean.cart.bo.CheckCartItemBo;
import com.cskaoyan.bean.cart.bo.UpdateCartItemBo;
import com.cskaoyan.bean.cart.vo.CartCheckoutData;
import com.cskaoyan.bean.cart.vo.CartData;
import com.cskaoyan.bean.config.ExpressConfig;
import com.cskaoyan.bean.wx_couponVO.DataBean;
import com.cskaoyan.bean.wx_couponVO.WxSelectListVO;
import com.cskaoyan.controller.AdminMallConfigController;
import com.cskaoyan.mapper.*;
import com.cskaoyan.service.promotionService.CouponService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.*;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private CartMapper cartMapper;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private AddressMapper addressMapper;
    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private AdminConfigService configService;
    @Autowired
    private CouponService couponService;
    @Autowired
    private WXAddressService wxAddressService;

    /**
     * 查查询用户购物车条目并作统计
     * @param userId
     * @return
     */
    @Override
    public CartData getUserCartIndex(int userId, Boolean checked) {
        List<Cart> carts = selectCartItem(userId, null, checked);//复用
//        CartExample example = new CartExample();
//        CartExample.Criteria criteria = example.createCriteria();
//        criteria.andDeletedEqualTo(false);
//        criteria.andUserIdEqualTo(userId);
//        List<Cart> carts = cartMapper.selectByExample(example);
        CartData cartData = new CartData(carts);
        return cartData;
    }

    /**
     * 返回用户购物车商品件数
     * @return
     */
    @Override
    public int cartGoodsCount(int userId) {
        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);
        criteria.andUserIdEqualTo(userId);
        List<Cart> carts = cartMapper.selectByExample(example);
        int count = 0;
        for (Cart cart : carts) {
            count += cart.getNumber();
        }
//        long count = cartMapper.countByExample(example);//本来重复的不想算个数的，还是算吧。这个取消
        return count;
    }

    /**
     * 添几商品到购物车
     * 方法复用-> number为负数可从购物车减少对应的数量
     * @param userId
     * @param bo
     * @return
     */             //TODO 除了加锁还有更好的办法吗
    //返回null 说明number为0没必要动数据库了
    //库存不做贪婪处理 没有就是不让加入 由商家自己设置多的余地
    @Transactional//事务 就算失败也只提示库存不足
    @Override//1 确认库存 2 添加（先查询是否已经有这个productId的deleted=false的单子，有就合并到里面，没有就新增） 3 减库存 4 返回购物车件数
    public synchronized Cart addToCart(int userId, AddToCartBo bo) throws SQLException {

        Integer number = bo.getNumber();
        Integer productId = bo.getProductId();

        ////确认库存 减库存 内部判断是否足够 失败抛异常
        GoodsProduct goodsProduct = goodsService.updateProductStock(productId, -number);

        //加入购物车
        List<Cart> carts = selectCartItem(userId, productId, null);
        Cart cart = null;
        if (carts.size() > 0) {
            //更新
            cart = carts.get(0);
            cart.setChecked(true);//添加会把状态修改为勾选
            updateUserCartItem(cart, goodsProduct, number);
        } else {
            //新增
            Integer newCartId = addItemToCart(userId, goodsProduct, bo);
            if (newCartId == null) return null;//number为0，不用增加直接返回了
            cart = new Cart();
            cart.setId(newCartId);
        }

        Cart cartItemAdded = cartMapper.selectByPrimaryKey(cart.getId());
        return cartItemAdded;
    }
    //服务 被调用
    private Integer addItemToCart(Integer userId, GoodsProduct goodsProduct, AddToCartBo bo) {

        Integer number = bo.getNumber();
        if (number == null || number == 0) return null;//复用于fastAdd会有0的情况

        Integer productId = bo.getProductId();
        Integer goodsId = bo.getGoodsId();
        Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
        String goodsSn = goods.getGoodsSn();
        String goodsName = goods.getName();
        BigDecimal price = goodsProduct.getPrice();
        String[] specifications = goodsProduct.getSpecifications();
        String url = goodsProduct.getUrl();
        BigDecimal cashAmount = price.multiply(BigDecimal.valueOf(number));

        Date now = new Date();
        Cart cart = new Cart();
        cart.setUserId(userId);
        cart.setGoodsId(goodsId);
        cart.setGoodsSn(goodsSn);
        cart.setGoodsName(goodsName);
        cart.setProductId(productId);
        cart.setPrice(cashAmount);
        cart.setNumber(number);
        cart.setSpecifications(specifications);
        cart.setPicUrl(url);
        cart.setAddTime(now);
        cart.setUpdateTime(now);

        cartMapper.insertSelective(cart);
        return cart.getId();
    }
    //作为子方法复用
    //选择购物车条目  数据库没瞎填数据，就只会返回1条或0条
    public List<Cart> selectCartItem(int userId, Integer productId, Boolean checked) {
        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);
        criteria.andUserIdEqualTo(userId);
        if (productId != null) {
            criteria.andProductIdEqualTo(productId);
        }
        if (checked != null) {
            criteria.andCheckedEqualTo(checked);
        }
        List<Cart> carts = cartMapper.selectByExample(example);
        return carts;
    }

    @Override
    public Cart getCartById(Integer id) {
        Cart cart = cartMapper.selectByPrimaryKey(id);
        return cart;
    }

    //更新购物车条目 可加 number为负数 可复用为减少
    private void updateUserCartItem(Cart cart, GoodsProduct product, Integer number) {
        Cart updateCart = new Cart();
        updateCart.setId(cart.getId());//购物车id必须
        if (number != null && number != 0 && product != null) {//比如添加到购物车时 修改条目，number为0不会改数据
            Integer sumNumber = cart.getNumber() + number;
            BigDecimal cashAmount = product.getPrice().multiply(BigDecimal.valueOf(sumNumber));
            updateCart.setNumber(sumNumber);
            updateCart.setPrice(cashAmount);
        }
        Boolean checked = cart.getChecked();
        if (checked != null) {//修改状态用
            updateCart.setChecked(checked);
        }

        Date now = new Date();
        updateCart.setUpdateTime(now);

        cartMapper.updateByPrimaryKeySelective(updateCart);
    }

    /**
     * 从购物车删除商品
     * @param userId
     * @param productIds
     */
    @Transactional
    @Override// 1 添加到库存 2 删除从购物车
    public void deleteFromCart(int userId, List<Integer> productIds) throws SQLException {
        //添加到库存
        for (Integer productId : productIds) {
            List<Cart> carts = selectCartItem(userId, productId, null);//之所以优先添加，因为先删除这个方法就查不到了
            if (carts.size() > 0) {
                Cart c = carts.get(0);
                Integer number = c.getNumber();
                goodsService.updateProductStock(productId, number);//返还库存
            }
        }

        //从购物车删除
        Cart cart = new Cart();
        cart.setDeleted(true);
        cart.setUpdateTime(new Date());

        CartExample example = new CartExample();
        CartExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andProductIdIn(productIds);//in (多个)

        cartMapper.updateByExampleSelective(cart, example);

    }

    /**
     * 勾选/取消勾选 购物车条目
     * 参数是数组（集合） 说明能多项 勾选，但是前端只传1个
     * @param userId
     * @param bo
     */
    @Override
    public void checkCartItems(Integer userId, CheckCartItemBo bo) {
        Boolean isChecked = bo.getIsChecked();
        List<Integer> productIds = bo.getProductIds();
        for (Integer productId : productIds) {
            List<Cart> carts = selectCartItem(userId, productId, null);
            if (carts.size() > 0) {
                Cart cart = carts.get(0);
                Integer id = cart.getId();

                Cart updateCart = new Cart();
                updateCart.setId(id);
                updateCart.setChecked(isChecked);

                updateUserCartItem(updateCart, null, null);//只更新勾选状态
            } else {
                throw new RuntimeException("尝试设置不存在的购物车条目勾选状态");//测试数据没攒好的话...
            }
        }
    }

    /**
     * 修改购物车条目数量
     * @param userId
     * @param bo
     * @return
     */
    @Transactional
    @Override//1 判断数量变化是增加还是减少 转化为 cart/add 添加到购物车 正数或负数
    public Cart updateCartItem(Integer userId, UpdateCartItemBo bo) throws SQLException {
        Integer cartId = bo.getId();
        Integer goodsId = bo.getGoodsId();
        Integer newNumber = bo.getNumber();
        Integer productId = bo.getProductId();
        //数量变化 是增加还是减少都统一处理
        Cart cart = cartMapper.selectByPrimaryKey(cartId);
        Integer numberInCart = cart.getNumber();

        Integer numberChange = newNumber - numberInCart;

        //转化为 添加到购物车 正数 或 负数
        AddToCartBo addToCartBo = new AddToCartBo(goodsId, numberChange, productId);

        Cart cartAdded = addToCart(userId, addToCartBo);

        return cartAdded;
    }

    /**
     * 快速添加
     * 如果购物车已经有这个产品，修改数量，以此为准，否则新增
     * @param userId
     * @param bo
     * @return
     */
    @Override//1 判断购物车是否有这个产品 2 有 转化为updateCartItem 2 没有 转化为 addToCart
    public Cart fastAdd(Integer userId, AddToCartBo bo) throws SQLException {
        //判断购物车是否有这个产品
        @NotNull Integer productId = bo.getProductId();
        @NotNull Integer number = bo.getNumber();
        @NotNull Integer goodsId = bo.getGoodsId();

        List<Cart> carts = selectCartItem(userId, productId, null);
        //有 转化为updateCartItem
        if (carts.size() > 0) {
            Cart cart = carts.get(0);
            Integer cartId = cart.getId();
            UpdateCartItemBo updateCartItemBo = new UpdateCartItemBo(productId, goodsId, number, cartId);
            return updateCartItem(userId, updateCartItemBo);
        }

        //没有 转化为 addToCart
        return addToCart(userId, bo);
    }

    /**
     * 下单前确认信息，团购，优惠卷，地址....所有有勾选的购物车条目 统计
     * @param userId
     * @param bo
     * @return
     */
    @Override
    public CartCheckoutData cartCheckout(int userId, CartCheckoutBo bo) throws Throwable {
        Integer addressId = bo.getAddressId();
        Integer cartId = bo.getCartId();//没用的，实测前端穿的数据是0或null 发现用处 0 全部 不为0
        Integer couponId = bo.getCouponId();
        Integer grouponRulesId = bo.getGrouponRulesId();//没用

        List<Cart> cartItems;
        BigDecimal checkedGoodsAmount = BigDecimal.ZERO;
        //获取购物车勾选条目
        if (cartId == null || cartId == 0) {//查询所有
            CartData cartData = getUserCartIndex(userId, true);
            cartItems = cartData.getCartList();
            CartData.CartTotalBean cartTotal = cartData.getCartTotal();
            checkedGoodsAmount = cartTotal.getCheckedGoodsAmount();
        } else {
            Cart cartById = getCartById(cartId);//指定购物车
            cartItems = new ArrayList<>();
            cartItems.add(cartById);
            checkedGoodsAmount = cartById.getPrice().multiply(BigDecimal.valueOf(cartById.getNumber()));
        }
        //获取地址 按 地址id
        Address address = wxAddressService.getAddressOrDefault(addressId, userId);
        //团购信息 TODO
        //优惠券信息
        BigDecimal couponPrice = getCouponPrice(userId, couponId, checkedGoodsAmount);
        //运费
        BigDecimal freightPrice = calcualteFreightPrice(checkedGoodsAmount);

        //封装到CartCheckoutData
        CartCheckoutData cartCheckoutData = new CartCheckoutData();
        cartCheckoutData.setCheckedGoodsList(cartItems);
        cartCheckoutData.setAddressId(addressId);
        cartCheckoutData.setCheckedAddress(address);
        cartCheckoutData.setFreightPrice(freightPrice);
        BigDecimal totalPrice = checkedGoodsAmount.add(freightPrice);
        cartCheckoutData.setActualPrice(totalPrice.subtract(couponPrice));
        cartCheckoutData.setOrderTotalPrice(totalPrice);
        cartCheckoutData.setGoodsTotalPrice(checkedGoodsAmount);


        //团购优惠相关
        cartCheckoutData.setCouponPrice(couponPrice);
//        cartCheckoutData.setGrouponRulesId();
//        cartCheckoutData.setCouponPrice();
//        cartCheckoutData.setAvailableCouponLength();

        return cartCheckoutData;
    }


    //默认前端能传过来couponId，就是可用的 => 实测前端传的不是null就是0 -1 发现 couponId = -1 时 不反回购物券
    private BigDecimal getCouponPrice(Integer userId, Integer couponId, BigDecimal checkedGoodsAmount) {
        BigDecimal couponPrice = BigDecimal.ZERO;
        if (couponId == null || couponId == -1) {//不用优惠卷
            return couponPrice;
        }

        Coupon coupon = couponService.couponRead(couponId);//用优惠券
        if (coupon != null) {
            return coupon.getDiscount();
        }

        //没有指定的就给最合适的
        List<DataBean> coupons = couponService.selectlistCoupon(userId);

        //选择可用的优惠券
        TreeMap<BigDecimal, BigDecimal> couponDataMap = new TreeMap<>();
        for (DataBean c : coupons) {
            BigDecimal min = BigDecimal.valueOf(Double.parseDouble(c.getMin()));
            BigDecimal discount = BigDecimal.valueOf(Double.parseDouble((c.getDiscount())));
            couponDataMap.put(min, discount);
        }
        for (BigDecimal min : couponDataMap.keySet()) {
            if (min.compareTo(checkedGoodsAmount) < 0) {
                couponPrice = couponDataMap.get(min);
            }
        }
        return couponPrice;
    }

    //计算运费
    //大于等于最低消费限制 0 ，小于 返回设定运费
    public BigDecimal calcualteFreightPrice(BigDecimal checkedGoodsAmount) throws Throwable {
        ExpressConfig expressConfig = configService.selectExpress();
        BigDecimal cskaoyanmall_express_freight_min;
        BigDecimal cskaoyanmall_express_freight_value;
        try {
            cskaoyanmall_express_freight_min = BigDecimal.valueOf(Integer.parseInt(expressConfig.getCskaoyanmall_express_freight_min()));
            cskaoyanmall_express_freight_value = BigDecimal.valueOf(Integer.parseInt(expressConfig.getCskaoyanmall_express_freight_value()));
        } catch (Exception e) {
            throw new Throwable("运费配置异常");
        }
        return checkedGoodsAmount.compareTo(cskaoyanmall_express_freight_min) >= 0  ? BigDecimal.ZERO : cskaoyanmall_express_freight_value;
    }
}
